package com.ai.service.made.impl;

import com.ai.check.CameraCheck;
import com.ai.common.constant.CommonArgs;
import com.ai.common.CommonResponse;
import com.ai.common.exception.ServiceException;
import com.ai.entity.cameraFunctions.functions.CameraFunctionsPO;
import com.ai.entity.function.FunctionPO;
import com.ai.entity.made.camera.*;
import com.ai.entity.network.L1ToIdentifySysMessage;
import com.ai.entity.server.ServerPO;
import com.ai.model.vo.BatchOperateCameraParam;
import com.ai.service.made.*;
import com.ai.util.HttpRequestUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AlgorithmCameraServiceImpl implements AlgorithmCameraService {

    @Resource
    CameraService cameraService;
    @Resource
    TimeIntervalService timeIntervalService;
    @Resource
    RegionsService regionsService;
    @Resource
    ServerService serverService;
    @Resource
    FunctionService functionService;

    @Resource
    CameraFunctionsService cameraFunctionsService;
    @Value("${api.live.url}")
    private String liveUrl;
    @Value("${api.ai.url}")
    private String aiUrl;
    /**
     * 创建线程池，批量开启摄像头时使用
     */
    public static ExecutorService executorService = Executors.newFixedThreadPool(3);
    /**
     * 打开摄像头
     *
     * @param cameraIdBO
     */
    @Override
    public CommonResponse onOpen(CameraIdBO cameraIdBO) {

        int state = 2;

//        摄像头什么时候有效--查看操作的摄像头是否存在
        CameraPO cameraPO = cameraService.getCameraOn(cameraIdBO);
        if (cameraPO == null) {
            return CommonResponse.error("请选择有效设备");
        }
        int id = cameraPO.getId();
//        根据摄像头的id和状态批量操作直播
        CommonResponse commonResponse = bulkSwitchForLive(id, state);
//        switchForLive(id,state)
        //返回结果码：1成功，-1失败
        if (commonResponse.getCode() != 200) {
            return commonResponse;
        }
        cameraPO = new CameraPO();
        cameraPO.setState(1);
        cameraService.update(cameraPO, new QueryWrapper<CameraPO>().eq("id", id));
        CommonArgs.CAMERA_HEARTBEAT_MAP.put(id, System.currentTimeMillis());

        return CommonResponse.ok("开启成功");
    }

    /**
     * 关闭摄像头
     *
     * @param cameraIdBO
     */
    @Override
    public CommonResponse onClose(CameraIdBO cameraIdBO) {


        int state = 3;
//        CameraCheck cameraCheck = new CameraCheck();
////        鉴权
//        if (cameraCheck.isCurrentID(cameraIdBO.getCurrentId())) {
//            return cameraCheck.resultData;
//        }

        CameraPO cameraPO = cameraService.getCameraOn(cameraIdBO);
        if (cameraPO == null) {
            return CommonResponse.error("请选择有效设备");
        }

        int cameraId = cameraPO.getId();

        CommonResponse CommonResponse = bulkSwitchForLive(cameraId, state);
        if (CommonResponse.getCode() != 200) {
            return CommonResponse;
        }

        cameraPO.setState(2);
        cameraService.updateById(cameraPO);

        CommonArgs.CAMERA_HEARTBEAT_MAP.remove(cameraId);
        return CommonResponse.ok("关闭成功");
    }

    /**
     * 通过功能开关算法
     *
     * @param type
     * @param state
     */
    @Override
    public void bulkSwitchForTelegram(int type, int state, Integer delayTime) {
        bulkSwitchForTelegram(type, state, delayTime, null);
    }

    @Override
    public void bulkSwitchForTelegram(int type, int state, Integer delayTime, Map<String, Object> extendedProperties) {
        FunctionPO functionPO = functionService.getOne(new QueryWrapper<FunctionPO>().eq("type", type));
        List<SwitchCameraAlgorithmBO> switchCameraAlgorithmBOList = cameraFunctionsService.getCameraByType(functionPO, state, extendedProperties);

        for (SwitchCameraAlgorithmBO switchCameraAlgorithmBO : switchCameraAlgorithmBOList) {

            CameraPO cameraPO = cameraService.getById(switchCameraAlgorithmBO.getCameraId());
            int serverId = cameraPO.getServerId();
            if (serverId == 0) {
                throw new ServiceException("该摄像头未绑定服务器");
            }
            ServerPO server = serverService.getById(serverId);
            String ip = server.getIp();
            Integer port = server.getPort();
            if (StringUtils.isEmpty(ip) || StringUtils.isEmpty(port) || port == 0) {
                throw new ServiceException("该摄像头所绑定服务器未设置IP或端口");
            }
            String url = ("http://" + ip + ":" + port + "/") + aiUrl;


            new Thread(() -> {
                //延时开关
                if (delayTime != null && delayTime > 0) {
                    log.info("信号延迟【" + delayTime + "秒】启动");
                    try {
                        Thread.sleep(delayTime * 1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }

                String param = JSONObject.toJSONString(switchCameraAlgorithmBO);
                log.info("启停算法的指令为： " + param);

                String s = HttpRequestUtil.sendPost(url, param);

                if (StringUtils.isEmpty(s) || "null".equals(s)) {
                    log.info("网络请求失败！");
                    return;
                }
                JSONObject o = JSONObject.parseObject(s);
                int resultCode = Integer.valueOf(o.getString("result_code"));
                log.info("摄像头操作" + ((resultCode == -1) ? "失败" : "成功"));
            }).start();
        }
    }

    @Override
    public CommonResponse detectionStart() {

        String url = "http://192.168.8.153:5000/predict";

//        String param = JSONObject.toJSONString(message);

        String param ="{\n" +
                "    \"cameraCode\":\"code\",\n" +
                "    \"cameraId\":1133,\n" +
                "    \"detectionTimes\":0,\n" +
                "    \"functions\":[\n" +
                "        {\n" +
                "            \"code\":\"2101\",\n" +
                "            \"id\":2101,\n" +
                "            \"spots\":[\n" +
                "                {\n" +
                "                    \"id\":100,\n" +
                "                    \"spots\":[\n" +
                "                        {\n" +
                "                            \"x\":1,\n" +
                "                            \"y\":1\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":959,\n" +
                "                            \"y\":1\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":959,\n" +
                "                            \"y\":539\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":1,\n" +
                "                            \"y\":539\n" +
                "                        }\n" +
                "                    ]\n" +
                "                }\n" +
                "            ],\n" +
                "            \"threshold\":0,\n" +
                "            \"timeIntervals\":[\n" +
                "                {\n" +
                "                    \"endTime\":\"235959\",\n" +
                "                    \"startTime\":\"000000\"\n" +
                "                }\n" +
                "            ],\n" +
                "            \"type\":1101\n" +
                "        }, {\n" +
                "            \"code\":\"2101\",\n" +
                "            \"id\":2101,\n" +
                "            \"spots\":[\n" +
                "                {\n" +
                "                    \"id\":100,\n" +
                "                    \"spots\":[\n" +
                "                        {\n" +
                "                            \"x\":1,\n" +
                "                            \"y\":1\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":959,\n" +
                "                            \"y\":1\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":959,\n" +
                "                            \"y\":539\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":1,\n" +
                "                            \"y\":539\n" +
                "                        }\n" +
                "                    ]\n" +
                "                }\n" +
                "            ],\n" +
                "            \"threshold\":0,\n" +
                "            \"timeIntervals\":[\n" +
                "                {\n" +
                "                    \"endTime\":\"235959\",\n" +
                "                    \"startTime\":\"000000\"\n" +
                "                }\n" +
                "            ],\n" +
                "            \"type\":1102\n" +
                "        }, {\n" +
                "            \"code\":\"2101\",\n" +
                "            \"id\":2101,\n" +
                "            \"spots\":[\n" +
                "                {\n" +
                "                    \"id\":100,\n" +
                "                    \"spots\":[\n" +
                "                        {\n" +
                "                            \"x\":1,\n" +
                "                            \"y\":1\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":959,\n" +
                "                            \"y\":1\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":959,\n" +
                "                            \"y\":539\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":1,\n" +
                "                            \"y\":539\n" +
                "                        }\n" +
                "                    ]\n" +
                "                }\n" +
                "            ],\n" +
                "            \"threshold\":0,\n" +
                "            \"timeIntervals\":[\n" +
                "                {\n" +
                "                    \"endTime\":\"235959\",\n" +
                "                    \"startTime\":\"000000\"\n" +
                "                }\n" +
                "            ],\n" +
                "            \"type\":1103\n" +
                "        }, {\n" +
                "            \"code\":\"2101\",\n" +
                "            \"id\":2101,\n" +
                "            \"spots\":[\n" +
                "                {\n" +
                "                    \"id\":100,\n" +
                "                    \"spots\":[\n" +
                "                        {\n" +
                "                            \"x\":1,\n" +
                "                            \"y\":1\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":959,\n" +
                "                            \"y\":1\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":959,\n" +
                "                            \"y\":539\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":1,\n" +
                "                            \"y\":539\n" +
                "                        }\n" +
                "                    ]\n" +
                "                }\n" +
                "            ],\n" +
                "            \"threshold\":0,\n" +
                "            \"timeIntervals\":[\n" +
                "                {\n" +
                "                    \"endTime\":\"235959\",\n" +
                "                    \"startTime\":\"000000\"\n" +
                "                }\n" +
                "            ],\n" +
                "            \"type\":1104\n" +
                "        }, {\n" +
                "            \"code\":\"2101\",\n" +
                "            \"id\":2101,\n" +
                "            \"spots\":[\n" +
                "                {\n" +
                "                    \"id\":100,\n" +
                "                    \"spots\":[\n" +
                "                        {\n" +
                "                            \"x\":1,\n" +
                "                            \"y\":1\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":959,\n" +
                "                            \"y\":1\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":959,\n" +
                "                            \"y\":539\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":1,\n" +
                "                            \"y\":539\n" +
                "                        }\n" +
                "                    ]\n" +
                "                }\n" +
                "            ],\n" +
                "            \"threshold\":0,\n" +
                "            \"timeIntervals\":[\n" +
                "                {\n" +
                "                    \"endTime\":\"235959\",\n" +
                "                    \"startTime\":\"000000\"\n" +
                "                }\n" +
                "            ],\n" +
                "            \"type\":1105\n" +
                "        }, {\n" +
                "            \"code\":\"2101\",\n" +
                "            \"id\":2101,\n" +
                "            \"spots\":[\n" +
                "                {\n" +
                "                    \"id\":100,\n" +
                "                    \"spots\":[\n" +
                "                        {\n" +
                "                            \"x\":1,\n" +
                "                            \"y\":1\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":959,\n" +
                "                            \"y\":1\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":959,\n" +
                "                            \"y\":539\n" +
                "                        },\n" +
                "                        {\n" +
                "                            \"x\":1,\n" +
                "                            \"y\":539\n" +
                "                        }\n" +
                "                    ]\n" +
                "                }\n" +
                "            ],\n" +
                "            \"threshold\":0,\n" +
                "            \"timeIntervals\":[\n" +
                "                {\n" +
                "                    \"endTime\":\"235959\",\n" +
                "                    \"startTime\":\"000000\"\n" +
                "                }\n" +
                "            ],\n" +
                "            \"type\":1105\n" +
                "        }\n" +
                "    ],\n" +
                "    \"ip\":\"192.168.8.153\",\n" +
                "    \"password\":\"123123\",\n" +
                "    \"planNo\":\"1234\",\n" +
                "    \"status\":4,\n" +
                "    \"streamWay\":1,\n" +
                "    \"url\":\"/home/server/cfc/video_file/bgs/phone_bgs/louxia1.mp4\",\n" +
                "    \"username\":\"camera_account\"\n" +
                "}";
        String s = HttpRequestUtil.sendPost(url, param);

        if (StringUtils.isEmpty(s) || "null".equals(s)) {
            log.info("网络请求失败！");
            return null;
        }

        JSONObject o = JSONObject.parseObject(s);
        int resultCode = Integer.valueOf(o.getString("resultCode"));
        log.info("摄像头操作" + ((resultCode == -1) ? "失败" : "成功"));

        return CommonResponse.ok("功能开启成功");
    }

    @Override
    public CommonResponse batchOpening(BatchOperateCameraParam batchOperateCameraParam) {

        //需要操作的摄像头id
        List<Integer> cameraIds = batchOperateCameraParam.getCameraIds();
        //开启还是关闭操作
        Integer state = batchOperateCameraParam.getState();

        if (CollectionUtils.isNotEmpty(cameraIds)){
            for (Integer cameraId : cameraIds) {
                //向线程池提交任务
                executorService.submit(()->{

                    CommonResponse response = bulkSwitchForLive(cameraId, state);

                    if (response.getCode()==200){
                        if (state==2  ){
                            //开启直播
                            cameraService.update(new UpdateWrapper<CameraPO>().eq("id", cameraId).set("state","1"));
                            CommonArgs.CAMERA_HEARTBEAT_MAP.put(cameraId, System.currentTimeMillis());
                        }else if (state==3 ){
                            //关闭直播
                            cameraService.update(new UpdateWrapper<CameraPO>().eq("id", cameraId).set("state","2"));
                            CommonArgs.CAMERA_HEARTBEAT_MAP.remove(cameraId);
                        }
                    }
                    //操作失败不做处理
                });
            }
        }
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return CommonResponse.ok("操作完成");
    }


    /**
     * 直播开关
     *
     * @param cameraId
     * @param state    2、3对应开启直播、关闭直播
     * @return
     */
    private CommonResponse bulkSwitchForLive(int cameraId, int state) {
        log.info("===========================  任务正在执行，当前线程：{}  ===========================",Thread.currentThread().getName());
        CameraPO cameraPO = cameraService.getById(cameraId);
        //服务器id
        int serverId = cameraPO.getServerId();
        if (serverId == 0) {
            return CommonResponse.error("该摄像头未绑定服务器");
        }
//        通过服务器ip获取对应的服务器
        ServerPO server = serverService.getById(serverId);
        if (null == server){
            return CommonResponse.error("服务器不存在，请检查摄像头后重新操作");
        }
        String ip = server.getIp();
        Integer port = server.getPort();
        if (StringUtils.isEmpty(ip) || StringUtils.isEmpty(port) || port == 0) {
            return CommonResponse.error("该摄像头所绑定服务器未设置IP或端口");
        }
        String url = ("http://" + ip + ":" + port + "/") + liveUrl;

        List<SwitchCameraFunctionAlgorithmBO> functionAlgorithmBOList =getAlgorithmFunctions(cameraId);

        String param;
//        摄像头与算法实体
        CameraSwitchAlgorithmBO algorithmBO = new CameraSwitchAlgorithmBO();
        if (state == 3) {
            //关闭直播
            algorithmBO.setCameraId(cameraId);
            algorithmBO.setState(3);
            algorithmBO.setUrl("");
            algorithmBO.setCameraCode(cameraPO.getCode());
            algorithmBO.setStatus(3);
            param = JSONObject.toJSONString(algorithmBO);

            log.info("------[" + cameraPO.getCode() + "]关闭直播");

        } else {
            //打开直播
            SwitchCameraAlgorithmBO switchCameraAlgorithmBO = new SwitchCameraAlgorithmBO();
            BeanUtils.copyProperties(cameraPO, switchCameraAlgorithmBO);
            switchCameraAlgorithmBO.setCameraId(cameraId);
            switchCameraAlgorithmBO.setCameraCode(cameraPO.getCode());
            switchCameraAlgorithmBO.setFunctions(functionAlgorithmBOList);
            log.info("------[" + cameraPO.getCode() + "]开启直播");

            switchCameraAlgorithmBO.setState(state);
            switchCameraAlgorithmBO.setStatus(state);
            param = JSONObject.toJSONString(switchCameraAlgorithmBO);
        }

        log.info("===========================  算法入参：{}  ===========================",param);


        String sr = HttpRequestUtil.sendPost(url, param);

        if (StringUtils.isEmpty(sr) || "null".equals(sr)) {//会返会null字符串么
            return CommonResponse.error("网络请求失败！");
        }
        //解析算法返回数据
        JSONObject jsonObject = JSONObject.parseObject(sr);
        String alReturnJson = jsonObject.toJSONString();

        log.info("===========================  算法返回数据：{} ===========================",alReturnJson);


        //返回结果码：1成功，-1失败
        int result = Integer. valueOf(jsonObject.getString("resultCode"));
        String msg = jsonObject.getString("resultMsg");
        if (result == -1) {
            return CommonResponse.error("摄像头操作失败：" + msg);
        }
        return CommonResponse.ok("操作成功");
    }

    /**
     * 获取摄像头所绑定方法的所有区域信息
     * @param cameraId
     * @return
     */
    private List<SwitchCameraFunctionAlgorithmBO> getAlgorithmFunctions( int cameraId ) {
        //获取当前摄像头所绑定的所有方法
        ArrayList<SwitchCameraFunctionAlgorithmBO> functionList = new ArrayList<>();
        List<CameraFunctionsPO> cameraFunctionsPOList= cameraFunctionsService.getBindFunctions(cameraId);


        for (CameraFunctionsPO cameraFunctionsPO : cameraFunctionsPOList) {

            FunctionPO functionPO = functionService.getById(cameraFunctionsPO.getFunctionId());
            int type = functionPO.getType();

            SwitchCameraFunctionAlgorithmBO functionAlgorithmBO = new SwitchCameraFunctionAlgorithmBO();
            functionAlgorithmBO.setId(cameraFunctionsPO.getId()).setType(type + "")
                    .setThreshold(cameraFunctionsPO.getThreshold())
                    .setSpecialOne(cameraFunctionsPO.getSpecialOne())
                    .setSpecialThree(cameraFunctionsPO.getSpecialTwo())
                    .setSpecialThree(cameraFunctionsPO.getSpecialThree())
                    .setSpecialFour(cameraFunctionsPO.getSpecialFour())
                    .setSpecialFive(cameraFunctionsPO.getSpecialFive())
                    .setTimeIntervals(timeIntervalService.getTimeIntervalList(cameraFunctionsPO.getId()))
                    .setSpots(regionsService.getSpots(cameraFunctionsPO.getId()));
            functionList.add(functionAlgorithmBO);
        }

        return functionList;
    }
}
